﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using Haozes.FxClient.CommUtil;
using Haozes.FxClient.Sip;
using System.Diagnostics;

namespace Haozes.FxClient.Core
{
    public class SipConnection : ISipConnection
    {
        private Socket socket = null;
        private volatile int callID = 1;
        private volatile bool isClosed = false;
        private Timer timerKeepLive;

        private byte[] recvBuffers = new byte[0x1000];
        private SipParser parser = new SipParser();
        public event EventHandler<ConversationArgs> MessageReceived;

        public SipConnection()
            : this(null)
        {
        }

        public SipConnection(Socket socket)
        {
            this.socket = socket;
            this.parser.RequestReceived += new EventHandler<SipRequestReceivedEventArgs>(this.Parser_RequestReceived);
            this.parser.ResponseReceived += new EventHandler<SipResponseReceivedEventArgs>(this.Parser_ResponseReceived);
            this.parser.MessageParsingFailed += new EventHandler(this.Parser_MessageParsingFailed);
        }

        public Socket SipSocket
        {
            get { return this.socket; }
            set { this.socket = value; }
        }

        public void Connect(string ip, string port)
        {
            try
            {
                this.socket = TcpHelper.CreateSocket(ip, port);
            }
            catch (Exception ex)
            {
                ErrManager.RaiseError(new FxErrArgs(ErrLevel.Fatal, ex));
            }
        }

        public System.Net.EndPoint LocalEndPoint
        {
            get { return this.socket.LocalEndPoint; }
        }

        public int NextCallID()
        {
            return ++this.callID;
        }

        private void KeepLive(object state)
        {
            // Socket socket = (Socket)state;
            SipMessage hpPacket = PacketFactory.GetKeepLoginPacket();
            this.Send(hpPacket);
        }

        public void StartListen()
        {
            this.ListenAsync(this.socket);
            int period = 3000 * 60;
            int dueTime = 10000;
            //心跳包一分钟调一次
            this.timerKeepLive = new Timer(new TimerCallback(this.KeepLive), this.socket, dueTime, period);
        }

        private void ListenAsync(object o)
        {
            if (this.isClosed)
                return;
            try
            {
                Socket state = o as Socket;
                state.BeginReceive(this.recvBuffers, 0, this.recvBuffers.Length, SocketFlags.None, new AsyncCallback(this.ReceiveData), state);
            }
            catch (Exception ex)
            {
                //LogUtil.Log.Error("ListenAsync异常:" + ex.ToString());
                return;
            }
        }

        private void ReceiveData(IAsyncResult iar)
        {
            int recv = 0;
            Socket remote = null;
            try
            {
                remote = (Socket)iar.AsyncState;
                recv = remote.EndReceive(iar);
                byte[] data = new byte[recv];
                Buffer.BlockCopy(this.recvBuffers, 0, data, 0, data.Length);
                if (data.Length < 2)
                    return;
                DebugWriter.WriteLine(">>>>>>>receive data:" + Encoding.UTF8.GetString(data, 0, data.Length));
                this.parser.Parse(data, 0, data.Length);
            }
            catch (SocketException ex)
            {
                string err = "ReceiveData异常:" + ex.ToString();

                if (ex.ErrorCode != /*(int)SocketError.OperationAborted*/ 995)
                {//上个线程退出
                    DebugWriter.WriteLine(err);
                    return;
                }
                //LogUtil.Log.Error(err);
                return;
            }
            this.ListenAsync(remote);
        }

        public void Send(SipMessage packet)
        {
            DebugWriter.WriteSendPacket(packet);
            try
            {
                TcpHelper.AsyncSend(this.socket, packet, this.SendCallback);
            }
            catch (SocketException ex)
            {
                DebugWriter.WriteLine("Send异常" + ex.ToString());
                ErrManager.RaiseError(new FxErrArgs(ErrLevel.Fatal, ex));
            }
        }

        public void SendCallback(IAsyncResult ar)
        {
            Socket socket = null;
            try
            {
                socket = ar as Socket;
            }
            catch (Exception exception)
            {
                string errInfo = string.Format("\r\nAysncSend:异步发送数据发生错误！\r\n端口与IP:{1}", socket.LocalEndPoint.ToString());
                //LogUtil.Log.Error(exception.ToString());
                ErrManager.RaiseError(new FxErrArgs(ErrLevel.Fatal, exception));
            }
        }

        public void Close()
        {
            this.isClosed = true;
            if (this.timerKeepLive == null)
                return;
            this.parser.RequestReceived -= new EventHandler<SipRequestReceivedEventArgs>(this.Parser_RequestReceived);
            this.parser.ResponseReceived -= new EventHandler<SipResponseReceivedEventArgs>(this.Parser_ResponseReceived);
            this.parser.MessageParsingFailed -= new EventHandler(this.Parser_MessageParsingFailed);

            this.timerKeepLive.Dispose();
            this.socket.Shutdown(SocketShutdown.Both);
            this.socket.Close();
        }

        private void Parser_MessageParsingFailed(object sender, EventArgs e)
        {
            DebugWriter.WriteLine("数据解析失败!");
            //LogUtil.Log.Error("数据解析失败");
        }

        private void Parser_ResponseReceived(object sender, SipResponseReceivedEventArgs e)
        {
            if (this.MessageReceived != null)
            {
                this.MessageReceived(this, new ConversationArgs(e.Response));
            }
        }

        private void Parser_RequestReceived(object sender, SipRequestReceivedEventArgs e)
        {
            if (this.MessageReceived != null)
            {
                this.MessageReceived(this, new ConversationArgs(e.Request));
            }
        }
    }
}
